<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  
  <link rel="stylesheet" href="/public/bootstrap.min.css">
  <link rel="stylesheet" href="/public/bootstrap-icons-141.css">
  <link rel="stylesheet" href="/public/style-light.css">
  
  <script src="/public/jquery.min.js"></script>
  <script src="/public/dayjs.min.js"></script>
  <script src="/public/bootstrap.bundle.min.js"></script>
  <script src="/public/util.js"></script>
  <script src="/public/filelist.js"></script>
  
  <title>Backup - localtags</title>
</head>
<body>
  <div id="root" class="container" style="max-width: 775px; min-width: 400px;"></div>
  <script>

const Backup_Bucket = 'Backup Bucket';
const Main_Bucket = 'Main Bucket';

const Alerts = CreateAlerts();

const [InfoBtn, InfoMsg] = CreateInfoPair('使用说明', [
  '可添加多个备份仓库，每个备份仓库都是一个独立、完整的备份。任何一个空文件夹都可以作为备份仓库，例如 D:\\localtags\\backup ',
  '(强烈建议把备份仓库与主仓库分别放在不同的物理硬盘或U盘里，鸡蛋不放在同一个篮子里)',
]);

const Navbar = {
  view: () => m('nav').addClass('navbar navbar-light bg-light').append([
    m('div').addClass('container-fluid').append([
      m('a').attr({title:'main menu',href:'/light/home',type:'button'})
        .addClass('btn btn-outline-dark').append(m('i').addClass('bi bi-house-door')),
      m('span').addClass('navbar-brand').append([
        'Backup', ' ', m(InfoBtn),    
      ]),
      m('a').attr({title:'refresh',href:'#',type:'button'}).addClass('btn btn-outline-dark')
        .append(m('i').addClass('bi bi-arrow-clockwise')).click(() => {window.location.reload()}),
    ]),
  ]),
};

const BucketList = cc('div');
const BucketsInfo = cc('div');
const SubmitBtnAera = cc('p');

const BucketInput = cc('textarea');
const AddBtn = cc('button');
const AddBucketArea = cc('div', null, [
  m(BucketInput).addClass('form-control').attr({placeholder:'backup bucket folder'}),
  m('p').addClass('text-end mt-2').append([
    m(AddBtn).text('add').addClass('btn btn-outline-primary').attr({type:'button'}),
  ]),
]);

BucketList.view = () => m('div')
    .attr({id:BucketList.raw_id}).addClass('accordion');

BucketList.prepend = (bucket, index) => {
  const Item = cc('div', 'bucket-'+index);
  const data_target = Item.id + ' .accordion-collapse';
  Item.view = () => m('div').attr({id:Item.raw_id}).addClass('accordion-item').append([
    m('h2').addClass('accordion-header').append([
      m('button').text(bucket).addClass('accordion-button collapsed')
          .attr({type:'button', 'data-bs-toggle':'collapse', 'data-bs-target':data_target}),
    ]),
    m('div').addClass('accordion-collapse collapse').attr({'data-bs-parent': BucketList.id}).append([
      m('div').addClass('accordion-body text-end').append([
        m('div').addClass('Buttons').append([
          m('button').text('use').attr({type:'button'}).addClass('UseBtn btn btn-sm btn-primary'),
          ' ',
          m('button').text('delete').attr({type:'button'}).addClass('DelBtn btn btn-sm btn-secondary'),
        ]),
        m('div').addClass('Confirm').hide().append([
          '仅从该列表中移除该项目，不会删除文件，是否继续执行？',
          m('button').text('yes').attr({type:'button'}).addClass('YesBtn btn btn-sm btn-danger'),
          ' ',
          m('button').text('no').attr({type:'button'}).addClass('NoBtn btn btn-sm btn-secondary'),
        ]),
      ]),
    ]),
  ]);

  $(BucketList.id).prepend(m(Item));

  const toggleConfirm = () => {
    $(Item.id + ' .Buttons').toggle();
    $(Item.id + ' .Confirm').toggle();
  };

  $(Item.id + ' .DelBtn').click(toggleConfirm);
  $(Item.id + ' .NoBtn').click(toggleConfirm);

  const yes_btn_id = Item.id + ' .YesBtn';
  $(yes_btn_id).click(() => {
    disable(yes_btn_id);
    Alerts.insert('info', '正在删除备份仓库......');
    const body = new FormData();
    body.append('index', index);
    ajax({method:'POST',url:'/api/delete-bk-bucket',alerts:Alerts,body:body},
        () => {
          // onSuccess
          Alerts.insert('info', '删除成功后会自动刷新页面');
          window.setTimeout(() => { window.location.reload(); }, 3000);
        },
        () => {
          // onFail
          enable(yes_btn_id);
        });
  });

  const use_btn_id = Item.id + ' .UseBtn';
  $(use_btn_id).click(() => {
    Alerts.insert('info', '正在获取备份仓库的状态信息......');
    Loading.show();
    $(BucketsInfo.id).html('');

    const longTime = window.setTimeout(() => {
      SubmitAlerts.insert('info', '正在校验备份仓库的文件完整性，请耐心等待......');
    }, 3000);

    const body = new FormData();
    body.append('bucket', bucket);
    ajax({method:'POST',url:'/api/get-buckets-info',alerts:Alerts,body:body},
        (info) => {
          // onSuccess
          Alerts.insert('success', '成功获取备份仓库的状态信息');

          const backup = create_bucket_info(Backup_Bucket, info['backup-bucket']);
          $(BucketsInfo.id).prepend(m(backup));
          backup.init();

          $(BucketsInfo.id).prepend(m('p').addClass('text-center my-1').append(
            m('i').addClass('bi bi-arrow-down').css('font-size', '2rem')
          ));

          const main = create_bucket_info(Main_Bucket, info['main-bucket']);
          $(BucketsInfo.id).prepend(m(main));
          main.init();

          $(SubmitBtnAera.id).show()
          SubmitBtnAera.init(main.damaged + backup.damaged);
          BucketList.formBody = body;
          scrollTop(BucketsInfo.id);
        }, null, () => {
          // onAlways
          Loading.hide();
          window.clearTimeout(longTime);
        });
  });
};

const SubmitAlerts = CreateAlerts();
const BackupBtn = cc('button');
const RepairBtn = cc('button');
const SubmitLoading = cc('div');

SubmitBtnAera.view = () => m('p').attr({id:SubmitBtnAera.raw_id}).append([
  m(SubmitLoading).addClass('text-center').hide().append([
    m('div').addClass('spinner-border text-primary').attr({role:'status'}).append(
      m('span').addClass('visually-hidden').text('Loading...')
    ),
  ]),
  m(BackupBtn).text('Backup').addClass('btn btn-primary').attr({type:'button'}).click(() => {
    Alerts.clear();
    $(SubmitLoading.id).show();
    SubmitAlerts.insert('info', '正在备份，请耐心等待......');
    const longTime = window.setTimeout(() => {
      SubmitAlerts.insert('info', '如果文件较多、较大，或U盘/硬盘速度慢，可能需要等待数分钟。');
    }, 5000);
    ajax({method:'POST',url:'/api/sync-backup',alerts:SubmitAlerts,buttonID:BackupBtn.id,body:BucketList.formBody},
        () => {
          // onSuccess
          SubmitAlerts.clear();
          SubmitAlerts.insert('success', '备份完成');
          $(BucketsInfo.id).html('');
          $(SubmitBtnAera.id).hide();
        }, null, () => {
          $(SubmitLoading.id).hide();
          window.clearTimeout(longTime);
        });
  }),
  m(RepairBtn).text('Repair').addClass('btn btn-primary').attr({type:'button'}).click(() => {
    Alerts.clear();
    $(SubmitLoading.id).show();
    SubmitAlerts.insert('info', '正在修复受损文件......');
    ajax({method:'POST',url:'/api/repair-files',alerts:SubmitAlerts,buttonID:BackupBtn.id,body:BucketList.formBody},
        () => {
          // onSuccess
          SubmitAlerts.clear();
          SubmitAlerts.insert('success', '修复完成');
          $(BucketsInfo.id).html('');
          $(SubmitBtnAera.id).hide();
        }, null, () => {
          $(SubmitLoading.id).hide();
        });
  }),
]);

SubmitBtnAera.init = (damaged_count) => {
  if (damaged_count > 0) {
    $(RepairBtn.id).show();
    $(BackupBtn.id).hide();
    SubmitAlerts.insert('info', `发现 ${damaged_count} 个损坏文件, 修复后才能备份`);
  } else {
    $(BackupBtn.id).show();
    $(RepairBtn.id).hide();
  }
}

$('#root').append([
  m(Navbar).addClass('mt-2 mb-5'),
  m(InfoMsg).hide(),
  m(AddBucketArea),
  m(Loading),
  m(Alerts),
  m(BucketList).addClass('my-5'),
  m(BucketsInfo),
  m(SubmitAlerts).addClass('my-3'),
  m(SubmitBtnAera).addClass('text-center').hide(),
  m(BottomLine),
]);

init()

function init() {

  $(AddBtn.id).click(() => {
    const bucketInput = $(BucketInput.id);
    const bucket = bucketInput.val().trim();
    if (!bucket) {
      bucketInput.focus();
      return;
    }

    Alerts.insert('info', '正在添加备份仓库......');

    const body = new FormData();
    body.append('bucket', bucket);

    disable(AddBtn.id);
    ajax({method:'POST',url:'/api/add-bk-bucket',alerts:Alerts,body:body},
      () => {
        // onSuccess
        Alerts.insert('info', '添加成功后会自动刷新页面');
        window.setTimeout(() => { window.location.reload(); }, 3000);
      }, () => {
        // onError
        enable(AddBtn.id);
      },
      () => {
        // onFail
        bucketInput.focus();
      });
  });

  ajax({method:'GET',url:'/api/get-bk-buckets',alerts:Alerts},
      (buckets) => {
        if (!buckets || buckets.length == 0) {
          Alerts.insert('primary', '请添加备份仓库，任何一个空文件夹都可以作为备份仓库，例如 D:\\localtags\\backup (注意，要先手动创建文件夹)');
          window.setTimeout(() => {$(BucketInput.id).focus()}, 100);
          return;
        }
        buckets.forEach(BucketList.prepend);
      }, null,
      () => {
        Loading.hide();
      });
}

function create_bucket_info(name, info) {
  const lastBackup = info.LastBackup ? 
      dayjs.unix(info.LastBackup).format('MMMM D, YYYY') : 'not yet';
  const lastChecked = info.LastChecked ? 
      dayjs.unix(info.LastChecked).format('MMMM D, YYYY') : 'not yet';

  const Damaged = cc('span');
  const BucketInfo = cc('div');
  const SearchBackupDamagedBtn = cc ('button');
  const DeleteDamagedBtn = cc('button');

  BucketInfo.view = () => m('div').attr({id:BucketInfo.raw_id}).addClass('card').append([
    m('div').addClass('card-header').append([
      m('span').text(name),
      m('br'),
      m('span').text(info.BucketLocation).addClass('small text-muted'),
    ]),
    m('div').addClass('card-body').append([
      m('p').text('上次备份时间: ' + lastBackup),
      m('p').text('上次校验时间: ' + lastChecked),
      m('p').text('占用空间: ' + fileSizeToString(info.TotalSize)),
      m('p').text('全部文件（个）: ' + info.AllFilesCount),
      m('p').append([
        '其中损坏文件（个）: ',
        m(Damaged).text(info.DamagedFilesCount), ' ',
        m('a').text('search').addClass('btn btn-sm btn-outline-secondary')
          .attr({type:'button',href:'/light/search?filter=damaged',target:'_blank'})
          .css('display', name == Main_Bucket && info.DamagedFilesCount > 0 ? 'inline' : 'none'),
        m(SearchBackupDamagedBtn).text('search').attr({type:'button'}).addClass('btn btn-sm btn-outline-secondary')
          .css('display', name == Backup_Bucket && info.DamagedFilesCount > 0 ? 'inline' : 'none')
          .click(() => {
            const bucketFolder = info.BucketLocation.replaceAll('\\', '/');
            SubmitAlerts.insert('primary',
              `按 F12 进入控制台输入命令 search_bk_damaged("${bucketFolder}") 可查找具体有哪些文件损坏。`);
          }),
        ' ',
        m(DeleteDamagedBtn).text('delete').attr({type:'button'}).addClass('btn btn-sm btn-outline-secondary')
          .css('display', name == Backup_Bucket && info.DamagedFilesCount > 0 ? 'inline' : 'none')
          .click(() => {
            const bucketFolder = info.BucketLocation.replaceAll('\\', '/');
            SubmitAlerts.insert('primary',
              `按 F12 进入控制台输入命令 DANGER_delete_backup_damaged("${bucketFolder}")
 可删除该备份仓库中的全部损坏文件。注意：请先尝试修复损坏文件，无法修复才使用该命令，如果频繁出现损坏文件请更换硬盘。`);
          }),
      ]),
    ]),
  ]);

  BucketInfo.init = () => {
    BucketInfo.damaged = info.DamagedFilesCount;
    if (BucketInfo.damaged > 0) {
      $(Damaged.id).addClass('text-danger fw-bold');
    }
  }

  return BucketInfo;
}

function DANGER_delete_backup_damaged(bucketFolder) {
  console.log(bucketFolder);
  console.log('正在删除备份仓库中的全部损坏文件......');
  const body = new FormData();
  body.append('bucket', bucketFolder);
  ajax({method:'POST',url:'/api/delete-backup-damaged',alerts:SubmitAlerts,body:body},
      () => {
        console.log('删除成功后会自动刷新页面。');
        window.setTimeout(() => { window.location.reload(); }, 3000);
      });
}

function search_bk_damaged(bucketFolder) {
  console.log(bucketFolder);
  console.log('查找备份仓库中的损坏文件......');
  const body = new FormData();
  body.append('bucket', bucketFolder);
  ajax({method:'POST',url:'/api/search-bk-damaged',body:body},
      (files) => {
        if (files == null) {
          console.log('未找到损坏文件');
          return;
        }
        let fileIDs = files.map(file => file.ID);
        console.log(fileIDs);
      });
}

</script>
</body>
</html>